/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package csm.uttils;

import java.io.*;

import csm.uttils.generics.Roster;

/**
 *
 * @author Carlos S. Moreno
 */
public class Archive {

    private String fileName;//Nombre del archivo con el que quiero trabajar
    private File file; //Variable en la q voy a cargar el archivo
    private ObjectInputStream oiStream;//Flujo que me permite leer objetos
    private FileInputStream fiStream;//Flujo que me permite leer archivos
    private FileReader fReader;
    private BufferedReader biStream; //Buffer para leer datos
    private ObjectOutputStream ooStream; //Flujo que me permite guardar objetos
    private FileOutputStream foStream;//Flujo que me permite guardar en archivos
    private FileWriter fWriter;
    private PrintWriter pWriter; //Buffer para escribir datos
    private boolean isOpen;//Variable que indica si hay un archivo abierto o no

    public Archive(String nombre) {
        fileName = nombre;
        isOpen = false;
        file = new File(fileName);
    }

    /**
     * Indicates if the references file does exist or not.
     * @return True if the file exist - False if does not.
     */
    private boolean exists() {
        return file.exists();
    }//Fin

    public String getExtension()
    {
        String ext = null;
        String s = file.getName();
        int i = s.lastIndexOf('.');

        if (i > 0 &&  i < s.length() - 1) {
            ext = s.substring(i+1).toLowerCase();
        }
        return ext;
    }

    public synchronized File[] getListFiles()
    {
        return file.listFiles();
    }
    
    /**
     * Open the file for reading
     */
    private synchronized void openArchiveReadObjects() throws IOException, Exception {
        try {
            if (!file.exists()) {
                file.createNewFile(); //SI el archivo no existe lo cre
            }
            file = new File(fileName);//Carga la variable con el archivo
            fiStream = new FileInputStream(file);//Prepara el flujo para leer archivos
            oiStream = new ObjectInputStream(fiStream);//Prepara el flujo para leer objetos

            isOpen = true;//Indica que el archivo se a abierto correctamente
        } catch (IOException e) {
            isOpen = false;
            throw e;
        } catch (Exception e) {
            isOpen = false;
            throw e;
        }
    }

/**
     * Open the file for reading
     */
    private synchronized void openArchiveReadStrings() throws IOException, Exception {
        try {
            if (!file.exists()) {
                file.createNewFile(); //SI el archivo no existe lo cre
            }
            file = new File(fileName);//Carga la variable con el archivo

            fReader = new FileReader(file);
            biStream = new BufferedReader(fReader);//Prepara el buffer
            isOpen = true;//Indica que el archivo se a abierto correctamente
        } catch (IOException e) {
            isOpen = false;
            throw e;
        } catch (Exception e) {
            isOpen = false;
            throw e;
        }
    }

    /**
     * Close the file opened for reading
     */
    private synchronized void closeArchiveReadObjects() {
        try {
            fiStream.close();//Cierra el flujo de lectura de archivo
            oiStream.close();//Cierra el flujo de lectura de objeto
            isOpen = false;//Indica que el archivo se ha cerrado
        } catch (Exception e) {
            System.out.println("Error at closing file: " + e.getMessage());
            isOpen = true;
        }
    }

    /**
     * Close the file opened for reading
     */
    private synchronized void closeArchiveReadStrings() {
        try {
            fReader.close();
            biStream.close();//Cierra el buffer
            isOpen = false;//Indica que el archivo se ha cerrado
        } catch (Exception e) {
            System.out.println("Error at closing file: " + e.getMessage());
            isOpen = true;
        }
    }

    /**
     * Read and return the saved object in the file.
     * @return the saved object
     */
    public synchronized Object readObject() {
        try {
            if (!isOpen) {
                openArchiveReadObjects();
            }

            return oiStream.readObject();
        } catch (IOException e) {
            System.out.println("Error at list creation: " + e.getMessage());
        } catch (ClassNotFoundException e) {
            System.out.println("Error at object creation:" + e.getMessage());
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            if (isOpen) {
                closeArchiveReadObjects();
            }
        }
        return new Object();
    }

    /**
     * Read and return the saved roster in the file.
     * @return the saved roster
     */
    public synchronized Roster readRoster() {
        Roster list = new Roster();

        try {
            if (!isOpen) {
                openArchiveReadObjects();
            }

            list = (Roster) oiStream.readObject();

        } catch (IOException e) {
            System.out.println("Error at list creation: " + e.getMessage());
        } catch (ClassNotFoundException e) {
            System.out.println("Error at object creation:" + e.getMessage());
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            closeArchiveReadObjects();
        }
        return list;
    }

    /**
     * Read and return the complete string in the file.
     * @return the saved roster
     */
    public synchronized String readString() {
        String text = "";
        try {
            if (!isOpen) {
                openArchiveReadStrings();
            }
            String line = biStream.readLine();
            String newLine = "";
            while (null != line)
            {
                text += newLine + line;
                line = biStream.readLine();
                newLine = "\n";
            }
        } catch (IOException e) {
            System.out.println("Error while string creation: " + e.getMessage());
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            closeArchiveReadStrings();
        }
        return text;
    }

    /**
     * Indicates if the file that is trying to read, is empty
     * @return True if the file is empty, False if it is not.
     */
    public boolean isEmpty() {
        try {
            return ((file.length() == 0) || !isOpen);
        } catch (SecurityException e) {
            System.out.println("Error verifying the file state.");
            System.exit(0);
        }
        return true;
    }

    /**
     * Open the file for writing
     */
    private synchronized void openArchiveWritingObjects() throws IOException, Exception {
        try {
            if (file.exists()) {
                file.delete();
            }
            foStream = new FileOutputStream(file);
            ooStream = new ObjectOutputStream(foStream);
            isOpen = true;
        } catch (IOException e) {
            isOpen = false;
            throw e;
        } catch (Exception e) {
            isOpen = false;
            throw e;
        }
    }

    /**
     * Open the file for writing Strings.
     * If the file exists, it delete it, and create it again.
     * @throws IOException
     * @throws FileNotFoundException
     * @throws Exception
     */
    private synchronized void openArchiveWritingStrings() throws IOException,
            FileNotFoundException, Exception {
        openArchiveWritingStrings(true);
    }


    /**
     * Open the file for writing Strings.
     * @param erase It determinates if it is necesary to delete the file if
     * exists.
     * @throws IOException
     * @throws FileNotFoundException
     * @throws Exception
     */
    private synchronized void openArchiveWritingStrings(boolean append) throws IOException,
            FileNotFoundException, Exception {
        try {
            fWriter = new FileWriter(file, append);
            pWriter = new PrintWriter(fWriter);
            isOpen = true;
        } catch (IOException e) {
            isOpen = false;
            throw e;
        }catch (Exception e) {
            isOpen = false;
            throw e;
        }
    }

    /**
     * Saves the file
     * @param arg Object to save.
     * @return True, if the file was saved successfully, False if it was not.
     */
    public synchronized boolean writeObject(Object arg) {
        boolean result = false;
        try {
            if (!isOpen) openArchiveWritingObjects();

            ooStream.writeObject(arg);
            result = true;
        } catch (IOException e) {
            System.out.println(e.getMessage());
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        finally
        {
            closeArchiveWritingObjects();
        }
        return result;
    }

    /**
     * Saves the complete roster on the opened file.
     * @param roster to be saved
     * @return True, if the operation was successful, False, if it was not.
     */
    public synchronized boolean writeRoster(Roster roster) {
        boolean result = false;
        try {
            if (!isOpen) openArchiveWritingObjects();

            ooStream.writeObject(roster);
            result = true;
        } catch (IOException e) {
            System.out.println(e.getMessage());
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        finally
        {
            closeArchiveWritingObjects();
        }
        return result;
    }

    /**
     * Saves the complete roster on the opened file.
     * @param arg String to be saved.
     * @param concat Deletes the file before save the string if it is false
     * @return True, if the operation was successful, False, if it was not.
     */
    public synchronized boolean writeString(String arg, boolean concat) {
        boolean result = false;
        try {
            if (!isOpen)
                openArchiveWritingStrings(concat);
            if(concat)
                arg = "/n" + arg;
            pWriter.print(arg);
            result = true;
        } catch (IOException e) {
            System.out.println(e.getMessage());
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        finally
        {
            closeArchiveWritingStrings();
        }
        return result;
    }

    /**
     * Close the file opened for writing
     */
    private synchronized void closeArchiveWritingObjects() {
        try {
            ooStream.close();
            foStream.close();
            isOpen = false;
        } catch (IOException e) {
            System.out.println("Error at closing the file: " + e.getMessage());
            isOpen = true;
        }
    }

    /**
     * Close the file opened for writing
     */
    private synchronized void closeArchiveWritingStrings() {
        try {
            //pWriter.flush();
            pWriter.close();
            fWriter.close();
            isOpen = false;
        } catch (IOException e) {
            System.out.println("Error at closing the file: " + e.getMessage());
            isOpen = true;
        }
    }
}
